{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example: combining MOD file ion channels with rxd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A version of this notebook may be run online via Google Colab at https://tinyurl.com/neuron-rxd-and-mod\n", " (make a copy or open in playground mode)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "NEURON's reaction-diffusion infrastructure can be used to readily allow intracellular concentrations to respond to currents generated in MOD files, as long as:\n", "\n", "- `nrn_region='i'` is specified for the `rxd.Region` (so that it knows it corresponds to the electrophysiology region of the inside of the cell), AND\n", "the name and charge of the ion/etc are given in the `rxd.Species` declaration.\n", "Satisfying the above two rules also allows MOD files to see intracellular concentrations.\n", "\n", "- 3D extracellular concentrations also interoperate with electrophysiology automatically as long as name and charge are specified.\n", "\n", "As a simple example, we consider a model with just a single point soma, of length and diameter 10 microns, with Hodgkin-Huxley kinetics (which uses the built in mod file `hh.mod`), and dynamic sodium (declared using rxd but without any additional kinetics)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup NEURON library and imports" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's import our usual NEURON libraries and definitions. Remember you can use either `um` or `µm` for micron." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2025-05-23T00:19:32.561974Z", "iopub.status.busy": "2025-05-23T00:19:32.561830Z", "iopub.status.idle": "2025-05-23T00:19:32.869507Z", "shell.execute_reply": "2025-05-23T00:19:32.869144Z" } }, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from neuron import h, rxd\n", "from neuron.units import mV, ms, um, mM\n", "\n", "## needed for standard run system\n", "h.load_file(\"stdrun.hoc\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now import `plotly`, a graphics library. (You could easily modify this code to use other graphics libraries like `matplotlib`, `plotnine`, or `bokeh`.)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2025-05-23T00:19:32.871231Z", "iopub.status.busy": "2025-05-23T00:19:32.871031Z", "iopub.status.idle": "2025-05-23T00:19:32.909417Z", "shell.execute_reply": "2025-05-23T00:19:32.909052Z" } }, "outputs": [], "source": [ "import plotly.graph_objects as go\n", "from plotly.subplots import make_subplots" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup the model" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2025-05-23T00:19:32.911322Z", "iopub.status.busy": "2025-05-23T00:19:32.910934Z", "iopub.status.idle": "2025-05-23T00:19:32.914908Z", "shell.execute_reply": "2025-05-23T00:19:32.914588Z" } }, "outputs": [], "source": [ "## define morphology\n", "soma = h.Section(name=\"soma\")\n", "soma.L = soma.diam = 10 * um\n", "\n", "## add ion channels (h.hh is built in, so always available)\n", "h.hh.insert(soma)\n", "\n", "## define cytosol. MUST specify nrn_region for concentrations to update\n", "cyt = rxd.Region([soma], name=\"cyt\", nrn_region=\"i\")\n", "\n", "## define sodium. MUST specify name and charge for concentrations to update\n", "na = rxd.Species(cyt, name=\"na\", charge=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we could have written `h.hh.insert(soma.wholetree())` to put Hodgkin-Huxley channels everywhere in the cell that the soma is part of, but since there is only one section, this is not required." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's also add an excitatory synapse to receive events (these will trigger the cell to spike)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2025-05-23T00:19:32.916339Z", "iopub.status.busy": "2025-05-23T00:19:32.916164Z", "iopub.status.idle": "2025-05-23T00:19:32.918446Z", "shell.execute_reply": "2025-05-23T00:19:32.918071Z" } }, "outputs": [], "source": [ "syn = h.ExpSyn(soma(0.5))\n", "syn.tau = 1 * ms\n", "syn.e = 0 * mV" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Add a stimulus" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The spike events themselves (two events, 15 ms apart starting at h.t=10*ms):" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2025-05-23T00:19:32.919829Z", "iopub.status.busy": "2025-05-23T00:19:32.919543Z", "iopub.status.idle": "2025-05-23T00:19:32.922114Z", "shell.execute_reply": "2025-05-23T00:19:32.921798Z" } }, "outputs": [], "source": [ "stim = h.NetStim()\n", "stim.interval = 15 * ms\n", "stim.number = 2\n", "stim.start = 10 * ms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Send those events to our synapse:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2025-05-23T00:19:32.923601Z", "iopub.status.busy": "2025-05-23T00:19:32.923259Z", "iopub.status.idle": "2025-05-23T00:19:32.926113Z", "shell.execute_reply": "2025-05-23T00:19:32.925735Z" } }, "outputs": [], "source": [ "nc = h.NetCon(stim, syn)\n", "nc.weight[0] = 0.001" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup recording variables" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2025-05-23T00:19:32.928155Z", "iopub.status.busy": "2025-05-23T00:19:32.927505Z", "iopub.status.idle": "2025-05-23T00:19:32.930701Z", "shell.execute_reply": "2025-05-23T00:19:32.930361Z" } }, "outputs": [], "source": [ "t = h.Vector().record(h._ref_t)\n", "v = h.Vector().record(soma(0.5)._ref_v)\n", "na_vec = h.Vector().record(soma(0.5)._ref_nai)\n", "ina = h.Vector().record(soma(0.5)._ref_ina)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialize and run the simulation" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2025-05-23T00:19:32.932629Z", "iopub.status.busy": "2025-05-23T00:19:32.931992Z", "iopub.status.idle": "2025-05-23T00:19:32.940869Z", "shell.execute_reply": "2025-05-23T00:19:32.940529Z" } }, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h.finitialize(-65 * mV)\n", "h.continuerun(50 * ms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot it" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2025-05-23T00:19:32.942946Z", "iopub.status.busy": "2025-05-23T00:19:32.942311Z", "iopub.status.idle": "2025-05-23T00:19:33.122485Z", "shell.execute_reply": "2025-05-23T00:19:33.122159Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "